from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from app.db.postgres import get_session
from app.db.mongo import db
from app.models import EvaluationReportHeader, EvaluationReport, EvaluationTemplate
from app.schemas.report import ReportVersionCreate, ReportVersionUpdate, ReportVersionRead


router = APIRouter(prefix="/report-versions", tags=["report-versions"])


@router.get("/by-header/{header_id}")
async def list_versions(header_id: str, page: int = Query(1, ge=1), page_size: int = Query(10, ge=1, le=200), session: AsyncSession = Depends(get_session)):
    total_res = await session.execute(select(func.count()).select_from(EvaluationReport).where(EvaluationReport.report_id == header_id))
    total = total_res.scalar() or 0
    res = await session.execute(
        select(EvaluationReport)
        .where(EvaluationReport.report_id == header_id)
        .order_by(EvaluationReport.version_no)
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    sql_items = res.scalars().all()
    items = []
    for x in sql_items:
        obj = ReportVersionRead.model_validate(x).model_dump()
        if x.mongo_report_id:
            from bson import ObjectId
            try:
                doc = await db.reports.find_one({"_id": ObjectId(str(x.mongo_report_id))})
            except Exception:
                doc = None
            if doc:
                rel_docx = (((doc or {}).get("exports") or {}).get("docx") or {}).get("rel_path")
                rel_pdf = (((doc or {}).get("exports") or {}).get("pdf") or {}).get("rel_path")
                if rel_docx:
                    obj["download_rel_path_docx"] = rel_docx
                if rel_pdf:
                    obj["download_rel_path_pdf"] = rel_pdf
        items.append(obj)
    return {"items": items, "total": total}


@router.post("/by-header/{header_id}", response_model=ReportVersionRead)
async def create_version(header_id: str, payload: ReportVersionCreate, session: AsyncSession = Depends(get_session)):
    hdr = await session.get(EvaluationReportHeader, header_id)
    if not hdr:
        raise HTTPException(status_code=404, detail="header_not_found")
    max_no = await session.execute(select(func.coalesce(func.max(EvaluationReport.version_no), 0)).where(EvaluationReport.report_id == header_id))
    next_no = (max_no.scalar() or 0) + 1
    obj = EvaluationReport(
        report_id=hdr.id,
        version_no=next_no,
        template_version_code=payload.template_version_code,
        title=payload.title,
        status='draft',
        adopted=False,
    )
    session.add(obj)
    await session.flush()
    await session.refresh(obj)
    await session.commit()
    return ReportVersionRead.model_validate(obj)


@router.get("/{version_id}", response_model=ReportVersionRead)
async def get_version(version_id: str, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationReport, version_id)
    if not obj:
        raise HTTPException(status_code=404, detail="version_not_found")
    return ReportVersionRead.model_validate(obj)


@router.put("/{version_id}", response_model=ReportVersionRead)
async def update_version(version_id: str, payload: ReportVersionUpdate, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationReport, version_id)
    if not obj:
        raise HTTPException(status_code=404, detail="version_not_found")
    if str(obj.status) != 'draft':
        raise HTTPException(status_code=400, detail="final_locked")
    for k, v in payload.model_dump(exclude_unset=True).items():
        setattr(obj, k, v)
    await session.flush()
    await session.refresh(obj)
    await session.commit()
    return ReportVersionRead.model_validate(obj)


@router.post("/{version_id}/finalize")
async def finalize_version(version_id: str, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationReport, version_id)
    if not obj:
        raise HTTPException(status_code=404, detail="version_not_found")
    obj.status = 'final'
    await session.flush()
    await session.commit()
    return {"ok": True}


@router.post("/{version_id}/adopt")
async def adopt_version(version_id: str, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationReport, version_id)
    if not obj:
        raise HTTPException(status_code=404, detail="version_not_found")
    if str(obj.status) != 'final':
        raise HTTPException(status_code=400, detail="only_final_can_adopt")
    hdr = await session.get(EvaluationReportHeader, obj.report_id)
    if not hdr:
        raise HTTPException(status_code=404, detail="header_not_found")
    prev = await session.execute(select(EvaluationReport).where(EvaluationReport.report_id == hdr.id, EvaluationReport.adopted == True))
    prev_obj = prev.scalars().first()
    if prev_obj and str(prev_obj.id) != str(obj.id):
        prev_obj.adopted = False
    obj.adopted = True
    hdr.adopted_version_id = obj.id
    await session.flush()
    await session.commit()
    return {"ok": True}


@router.delete("/{version_id}")
async def delete_version(version_id: str, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationReport, version_id)
    if not obj:
        raise HTTPException(status_code=404, detail="version_not_found")
    if obj.adopted:
        raise HTTPException(status_code=400, detail="adopted_cannot_delete")
    await session.delete(obj)
    await session.commit()
    return {"ok": True}


@router.post("/by-header/{header_id}/clone-latest", response_model=ReportVersionRead)
async def clone_latest(header_id: str, session: AsyncSession = Depends(get_session)):
    hdr = await session.get(EvaluationReportHeader, header_id)
    if not hdr:
        raise HTTPException(status_code=404, detail="header_not_found")
    latest = await session.execute(select(EvaluationReport).where(EvaluationReport.report_id == header_id).order_by(EvaluationReport.version_no.desc()).limit(1))
    src = latest.scalars().first()
    max_no = src.version_no if src else 0
    obj = EvaluationReport(
        report_id=hdr.id,
        version_no=max_no + 1,
        template_version_code=src.template_version_code if src else '',
        title=src.title if src else hdr.name,
        status='draft',
        adopted=False,
        parent_version_id=src.id if src else None,
    )
    session.add(obj)
    await session.flush()
    await session.refresh(obj)
    await session.commit()
    return ReportVersionRead.model_validate(obj)
